// Copyright (C) joyinter
// All rights reserved.
// 
// Author : Jiang Li
// Date   : 2005-01-26

#include "stdafx.h"
#include <common/netmsg/netmsg.h>
#include "svr_asyncstop.h"
#include "svr_server.h"
#include "svr_userpool.h"
#include "svr_user.h"
#include "svr_showinfo.h"
#include "svr_asyncexec.h"
#include "ui_svrwnd.h"

namespace JoyServer
{

// CJoyServerAsyncStop

CJoyServerAsyncStop::CJoyServerAsyncStop()
{
}

CJoyServerAsyncStop::~CJoyServerAsyncStop()
{
}

bool CJoyServerAsyncStop::Create(CJoyServerWnd* serverWnd)
{
    m_serverWnd = serverWnd;
    return true;
}

void CJoyServerAsyncStop::Destroy()
{
}

void CJoyServerAsyncStop::CloseAcceptor()
{
    m_serverWnd->m_server->m_userPool->m_acceptor->Close();
}

void CJoyServerAsyncStop::CloseTimer()
{
}

void CJoyServerAsyncStop::StopBegin()
{
    CJoyServer* pServer = m_serverWnd->m_server;
    if(pServer == NULL)
    {
        StopEnd();
        return;
    }
    // if stopping, exit.
    if(pServer->m_stopping)
    {
        return;
    }
    CJoyShowInfo* showInfo = pServer->m_showInfo;

    // do not accept any user.
    CloseAcceptor();

    showInfo->QueueTimeColorText(InfoColor_Special,
        "Asynchronous stop server begin. Accepter closed.\n");

    m_serverWnd->SetTimer(JOY_ASYNC_STOP_TIMER, 500, NULL);
}

void CJoyServerAsyncStop::StopTick()
{
    CJoyServer* pServer = m_serverWnd->m_server;
    if(pServer == NULL)
    {
        StopEnd();
        return;
    }
    // if stopping, exit.
    if(pServer->m_stopping)
    {
        return;
    }
    CJoyShowInfo* showInfo = pServer->m_showInfo;

    const int MAX_QUEUED_COUNT = 64;

    // too many queued objects.
    int queuedCount = pServer->m_asyncExec->QueuedCount();
    if(queuedCount > MAX_QUEUED_COUNT)
    {
        showInfo->QueueTimeColorText(InfoColor_Special,
            "too many queued objects in the async executor. currnt %d.\n", queuedCount);
        return;
    }

    CJoyServer::CUserSets userSets;
    {
        CJoyAutoCS gate(pServer->m_userSetsLock);
        userSets.Append(pServer->m_userSets);
    }
    int c = (int)userSets.GetCount();
    for(int i = 0; i < c; ++ i)
    {
        CJoyUserSet* userSet = userSets[i];
        if(userSet->m_userIds.IsEmpty())
        {
            continue;
        }

        CJoyAutoCS gate(userSet->m_userLock);
        CJoyUserSet::CUserIdMap& userIds = userSet->m_userIds;
        POSITION pos = userIds.GetStartPosition();
        int nKicked = 0;
        while(pos)
        {
            UINT userId;
            CJoyUser* pUser;
            userIds.GetNextAssoc(pos, userId, pUser);
            if(pUser->m_kicked)
            {
                continue;
            }

            pUser->Kick(JoyMessage::Error_ServerDown);
            ++ nKicked;

            queuedCount = pServer->m_asyncExec->QueuedCount();
            if(queuedCount > MAX_QUEUED_COUNT)
            {
                break;
            }
        }
        showInfo->QueueTimeColorText(InfoColor_Special,
            "%d users kicked.\n", nKicked);
        return;
    }

    StopEnd();
}

void CJoyServerAsyncStop::StopEnd()
{
    CJoyServer* pServer = m_serverWnd->m_server;
    if(pServer == NULL)
    {
        StopEnd();
        return;
    }
    // if stopping, exit.
    if(pServer->m_stopping)
    {
        return;
    }
    CJoyShowInfo* showInfo = pServer->m_showInfo;

    m_serverWnd->KillTimer(JOY_ASYNC_STOP_TIMER);

    showInfo->QueueTimeColorText(InfoColor_Special,
        "Asynchronous stop server end.\n");

    m_serverWnd->StopServer();
}

} // namespace JoyServer